﻿/*  
 * Helix Engine
 * http://helixengine.codeplex.com/
 * 
 * Copyright (c) 2010 - 2011 Joe Hegarty
 *  
 * This source code is subject to the terms of the Microsoft Public License (Ms-PL). 
 *  
 * Redistribution and use in source and binary forms, with or without modification, 
 * is permitted provided that redistributions of the source code retain the above 
 * copyright notices and this file header. 
 * 
 * For details please see http://www.opensource.org/licenses/ms-pl.html 
 *  
 * All other rights reserved. 
 *
 */  


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace HelixEngine.Maths
{
    /// <remarks>
    /// 
    /// </remarks>
    public struct Vector2
    {
        double _x;
        double _y;
        static Vector2 _zero = new Vector2(0, 0);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public Vector2(double x, double y)
        {
            _x = x;
            _y = y;
        }

        /// <summary>
        /// 
        /// </summary>
        public double X
        {
            get
            {
                return _x;
            }

            set
            {
                _x = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public double Y
        {
            get
            {
                return _y;
            }

            set
            {
                _y = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        static public Vector2 Zero
        {
            get
            {
                return _zero;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static Vector2 operator -(Vector2 Vector2)
        {
            return new Vector2(-Vector2.X, -Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static Vector2 operator -(Vector2 Vector21, Vector2 Vector22)
        {
            return Vector2.Subtract(Vector21, Vector22);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static bool operator !=(Vector2 Vector21, Vector2 Vector22)
        {
            return !Vector2.Equals(Vector21, Vector22);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scalar"></param>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static Vector2 operator *(double scalar, Vector2 Vector2)
        {
            return Vector2.Multiply(scalar, Vector2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="scalar"></param>
        /// <returns></returns>
        public static Vector2 operator *(Vector2 Vector2, double scalar)
        {
            return new Vector2(scalar * Vector2.X, scalar * Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="matrix"></param>
        /// <returns></returns>
        public static Vector2 operator *(Vector2 Vector2, Matrix matrix)
        {
            throw (new NotImplementedException("Not Implemented"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static double operator *(Vector2 Vector21, Vector2 Vector22)
        {
            return Vector2.Multiply(Vector21, Vector22);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="scalar"></param>
        /// <returns></returns>
        public static Vector2 operator /(Vector2 Vector2, double scalar)
        {
            return new Vector2(Vector2.X / scalar, Vector2.Y / scalar);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Point operator +(Vector2 Vector2, Point point)
        {
            return new Point(point.X + Vector2.X, point.Y + Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static Point operator +(Point point, Vector2 Vector2)
        {
            return new Point(point.X + Vector2.X, point.Y + Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static Point operator -(Point point, Vector2 Vector2)
        {
            return new Point(point.X - Vector2.X, point.Y - Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static Vector2 operator +(Vector2 Vector21, Vector2 Vector22)
        {
            return new Vector2(Vector21.X + Vector22.X, Vector21.Y + Vector22.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static bool operator ==(Vector2 Vector21, Vector2 Vector22)
        {
            return Vector2.Equals(Vector21, Vector22);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static explicit operator Point(Vector2 Vector2)
        {
            return new Point(Vector2.X, Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static explicit operator Size(Vector2 Vector2)
        {
            return new Size(Math.Abs(Vector2.X), Math.Abs(Vector2.Y));
        }

        /// <summary>
        /// 
        /// </summary>
        public double Length
        {
            get
            {
                return Math.Sqrt(LengthSquared);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public double LengthSquared
        {
            get
            {
                return X * X + Y * Y;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Point Add(Vector2 Vector2, Point point)
        {
            return new Point(Vector2.X + point.X, Vector2.Y + point.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static Vector2 Add(Vector2 Vector21, Vector2 Vector22)
        {
            return new Vector2(Vector21.X + Vector22.X, Vector21.Y + Vector22.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static double AngleBetween(Vector2 Vector21, Vector2 Vector22)
        {
            throw (new NotImplementedException("Not Implemented"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static double CrossProduct(Vector2 Vector21, Vector2 Vector22)
        {
            return (Vector21.X * Vector22.Y) - (Vector21.Y * Vector22.X);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static double Determinant(Vector2 Vector21, Vector2 Vector22)
        {
            throw (new NotImplementedException("Not Implemented"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="scalar"></param>
        /// <returns></returns>
        public static Vector2 Divide(Vector2 Vector2, double scalar)
        {
            return new Vector2(Vector2.X / scalar, Vector2.Y / scalar);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            if (o is Vector2)
            {
                Vector2 v = (Vector2)o;
                return this.Equals(v);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Equals(Vector2 value)
        {
            return Vector2.Equals(this, value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static bool Equals(Vector2 Vector21, Vector2 Vector22)
        {
            return (Vector21.X == Vector22.X && Vector21.Y == Vector22.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            int x = (int)X;
            int y = (int)Y;
            int fx = (int)((X - x) * 10000);
            int fy = (int)((Y - y) * 10000);
            return x ^ y ^ fx ^ fy;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scalar"></param>
        /// <param name="Vector2"></param>
        /// <returns></returns>
        public static Vector2 Multiply(double scalar, Vector2 Vector2)
        {
            return new Vector2(scalar * Vector2.X, scalar * Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="scalar"></param>
        /// <returns></returns>
        public static Vector2 Multiply(Vector2 Vector2, double scalar)
        {
            return new Vector2(scalar * Vector2.X, scalar * Vector2.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector2"></param>
        /// <param name="matrix"></param>
        /// <returns></returns>
        public static Vector2 Multiply(Vector2 Vector2, Matrix matrix)
        {
            throw (new NotImplementedException("Not Implemented"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static double Multiply(Vector2 Vector21, Vector2 Vector22)
        {
            return (Vector21.X * Vector22.X + Vector21.Y * Vector22.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        public void Negate()
        {
            X = -X;
            Y = -Y;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Normalize()
        {
            double length = Length;
            X /= length;
            Y /= length;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Vector2 Parse(string source)
        {
            Vector2 v = Vector2.Zero;
            try
            {
                string[] s = source.Split(",".ToCharArray());
                v.X = double.Parse(s[0]);
                v.Y = double.Parse(s[1]);
            }
            catch (Exception e)
            {
                throw new FormatException("Vector2 string is not in the correct format. " + e.Message);
            }
            return v;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Vector21"></param>
        /// <param name="Vector22"></param>
        /// <returns></returns>
        public static Vector2 Subtract(Vector2 Vector21, Vector2 Vector22)
        {
            return new Vector2(Vector21.X - Vector22.X, Vector21.Y - Vector22.Y);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return X.ToString() + "," + Y.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public string ToString(IFormatProvider provider)
        {
            throw (new NotImplementedException("Not Implemented"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Point ToPoint()
        {
            return new Point(_x, _y);
        }
    }
}
